#include "connector.hpp"
#include "logger.hpp"
#include "sock5client.hpp"

namespace oraysock5 {
Connector::Connector(std::shared_ptr<IPAddress> connect_addr)
    : ConnectEvent(connect_addr)
{
}
Connector::~Connector()
{
    if (active_ == CloseType::CLIENT_CLOSE) {
        LOG_INFO << "连接远端客户端主动关闭连接 "
                 << "[ip:" << connect_addr()->ip() << ":" << connect_addr()->port() << "]";
    } else if (active_ == CloseType::SERVER_CLOSE) {
        LOG_INFO << "远端服务器主动关闭连接 "
                 << "[ip:" << connect_addr()->ip() << ":" << connect_addr()->port() << "]";
    } else if (active_ == CloseType::CONNECT_FAIL) {
        LOG_INFO << "连接远端服务器失败 "
                 << "[ip:" << connect_addr()->ip() << ":" << connect_addr()->port() << "]";
    }
    std::shared_ptr<Sock5Client> cli = sock5client_.lock();
    if (cli) {
        cli->close(CloseType::SERVER_CLOSE);
    }
}

void Connector::success()
{
    LOG_INFO << "连接远端服务器成功 [ip:" << connect_addr()->ip() << ":" << connect_addr()->port() << "]";
    //发送连接成功回应
    struct sockaddr_in loc_addr;
    socklen_t len = 0;
    len = sizeof(loc_addr);
    memset(&loc_addr, 0, len);
    if (-1 == getsockname(iobuf_->fd(), (struct sockaddr*)&loc_addr, &len)) {
        THROW_EXCEPTION("call getsockname");
    }
    char ipbuff[INET_ADDRSTRLEN] = { 0 };
    struct sockaddr_in* in4 = (struct sockaddr_in*)&loc_addr;
    if (inet_ntop(AF_INET, &in4->sin_addr, ipbuff, INET_ADDRSTRLEN) == nullptr) {
        THROW_EXCEPTION("call inet_ntop");
    }
    unsigned long ipint = inet_addr(ipbuff);
    char send[10] = { 0 };
    send[0] = 0x05;
    send[1] = 0x00;
    send[2] = 0x01;
    send[3] = 0x01;
    memcpy(send + 4, &ipint, 4);
    uint16_t port = htons(in4->sin_port);
    memcpy(send + 8, &port, 2);
    std::shared_ptr<Sock5Client> cli = sock5client_.lock();
    if (cli) {
        cli->iobuf()->write(send, sizeof(send));
        LOG_INFO << "发送连接成功回应";
    }
}

InputResult Connector::input()
{
    std::shared_ptr<Sock5Client> cli = sock5client_.lock();
    if (cli) {
        cli->iobuf()->write(iobuf_->inputbuffer());
        return InputResult::SUCCESS;
    } else {
        return InputResult::INITIATIVE_CLOSE;
    }
}

void Connector::close(CloseType active)
{
    active_ = active;
}

void Connector::timerout(CloseType active)
{
    LOG_INFO << "检测到与服务器没有心跳超时 [ip:" << connect_addr()->ip() << ":" << connect_addr()->port() << "]";
    close(active);
}

}
